package com.yiwenup.struct._06_graph.base;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * 封装图的节点和边信息
 **/
@SuppressWarnings("unchecked")
public abstract class AbstractGraph<V, W> {
    protected Graph.WeightManager<W> weightManager;

    public AbstractGraph(Graph.WeightManager<W> weightManager) {
        this.weightManager = weightManager;
    }

    /**
     * 顶点
     */
    public class Vertex {
        /**
         * 顶点存储的元素
         */
        public V value;
        /**
         * 入度
         */
        public Set<Edge> inEdges = new HashSet<>();
        /**
         * 出度
         */
        public Set<Edge> outEdges = new HashSet<>();

        public Vertex(V value) {
            this.value = value;
        }

        @Override
        public boolean equals(Object obj) {
            return Objects.equals(((Vertex) obj).value, this.value);
        }

        @Override
        public int hashCode() {
            return value == null ? 0 : value.hashCode();
        }

        @Override
        public String toString() {
            return value == null ? "null" : value.toString();
        }
    }

    /**
     * 边
     */
    public class Edge {
        /**
         * 顶点
         */
        public Vertex from;
        /**
         * 终点
         */
        public Vertex to;
        /**
         * 权值
         */
        public W weight;

        public Edge(Vertex from, Vertex to) {
            this.from = from;
            this.to = to;
        }

        public Graph.EdgeInfo<V, W> info() {
            return new Graph.EdgeInfo<V, W>(from.value, to.value, weight);
        }

        @Override
        public boolean equals(Object obj) {
            Edge another = (Edge) obj;
            return Objects.equals(another.from, this.from) && Objects.equals(another.to, this.to);
        }

        @Override
        public int hashCode() {
            return from.hashCode() * 31 + to.hashCode();
        }

        @Override
        public String toString() {
            return "Edge{" +
                    "from=" + from +
                    ", to=" + to +
                    ", weight=" + weight +
                    '}';
        }
    }
}
